package controlsystem;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import managesystem.Buddy;
import managesystem.Student;
import managesystem.StudentManager;
import tracksystem.Activity;
import tracksystem.OtherActivity;
import tracksystem.SchoolActivity;

/**
 * @author Ine Janssens en Serge Hendrickx
 * Berekent de statistieken 
 * De tijd is altijd in miliseconden
 */


 public class StatisticsController {

	private static final double convToHours = 0.0000002777777777777777;
	
	
//	private static double round(double d) {
//		long temp=(long)((d*Math.pow(10,2)));
//		double ret = (((double)temp/Math.pow(10,2)));
//		return ret;
//		}
	
	/**
	 * methode om uren af te ronden
	 * @param d de tijd in uren
	 * @return de tijd afgerond naar 2 decimalen
	 */
	private static double round(double d) {
        DecimalFormat twoDForm = new DecimalFormat("#.##");
        return Double.valueOf(twoDForm.format(d));
		}
	
	
	/** Genereert totale tijd per vak
	* @param currStud de student
	* @return Hashmap met Vakken en tijd per vak
	*/
	static public HashMap<Course,Double> getTimePerCourse(Student currStud){
		HashMap<Course,Double> timePerCourse = new HashMap<Course, Double>();
		List<Course> courses = currStud.getCourses();
		//een hashmap vullen met de vakken en tijden
		Iterator<Course> iterator = courses.iterator();
		while(iterator.hasNext() == true){
			Course course = iterator.next();
			double time = round(timeOfCourse(course, currStud)*convToHours);
			timePerCourse.put(course, time);
		}
		return timePerCourse;
	}
	
	/**
	 * De tijd die besteed is aan een vak door een bepaalde student
	 * @param currStud de student
	 * @param course het vak waarvoor de tijd berekend moet worden
	 * @return de tijd die besteed is aan dat vak door die student
	 */
	static private double timeOfCourse(Course course, Student currStud){
		ArrayList<SchoolActivity> activities = currStud.getOnlySchoolActs();
		long time = 0;
		Iterator<SchoolActivity> iterator = activities.iterator();
		while(iterator.hasNext() == true){
			SchoolActivity activity = iterator.next();
			if(activity.getCourse().getName().equals(course.getName())){
				time = time + activity.getDuration();
			}
		}
		return round(time);
	}
	
	/** Genereert totale gestudeerde tijd ten opzichte van ideale tijd voor een bepaald vak
	* @param currStud de student
	* @param course het vak waarvoor de tijd berekend moet worden
	* @return Hashmap gestudeerde tijd, ideale tijd
	*/
	static public HashMap<Double,Double> getTimeVsIdeal(Course course, Student currStud){
		double ideal = round(course.getStudyPoints()*(27500*60*60)*convToHours);
		double time = round(timeOfCourse(course, currStud)*convToHours);
		HashMap<Double,Double> timeVsIdeal = new HashMap<Double,Double>();
		timeVsIdeal.put(time, ideal);
		return timeVsIdeal;
	}
	
	

	/** Genereert de uren per week
	* @param currStud de student
	* @return ArrayList met als index de week van het jaar en als element bijhorend aantal uren.
	*/
	
	static public ArrayList<Long> getHoursPerWeek(Student currStud){
		ArrayList<SchoolActivity> activities = currStud.getOnlySchoolActs();
		ArrayList<Long> hoursPerWeek = new ArrayList<Long>();
		//vult de arraylist op met de uren per week (met nummer van de week, het nummer van de index)
		for(int i = 0; i<activities.size(); i++){
			SchoolActivity activity = activities.get(i);
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(activity.getStart());
			long duration = activity.getDuration();
			long uren = duration/(1000*60*60);
			int week = calendar.get(Calendar.WEEK_OF_YEAR);
			long totalHoursPerWeek = hoursPerWeek.get(week) + uren;
			hoursPerWeek.add(week, totalHoursPerWeek);
		}
		return hoursPerWeek;
	}
	
	
	/**
	 * genereert per type de tijd
	 * @param course de course waarvan per type de tijd berekend wordt
	 * @param currStud de student
	 * @return hashmap met per type de gespendeerde tijd
	 */
	static public HashMap<String,Double> getDistribution(Course course, Student currStud){
		HashMap<String, Double> courseDistribution = new HashMap<String, Double>();
		courseDistribution.put("lesson", courseTimePerType("lesson", course,currStud));
		courseDistribution.put("exercise",courseTimePerType("exercise", course,currStud));
		courseDistribution.put("self",courseTimePerType("self", course,currStud));
		
		return courseDistribution;
	}
	
	/**
	 * genereert de tijd gespendeerd van een type
	 * @param type "hoorcollege", "oefenzitting" of "studietijd"
	 * @param course de les waarvan de tijd berekent wordt
	 * @param currStud de student
	 * @return
	 */
	static private double courseTimePerType(String type, Course course,Student currStud){
		double time = 0;
		ArrayList<SchoolActivity> activities = currStud.getOnlySchoolActs();
		for(int i = 0; i<activities.size(); i++){
		
		SchoolActivity activity = activities.get(i);
			Course activityCourse = activity.getCourse();
			if(activityCourse.getName().equals(course.getName()) && activity.getType().equals(type)){
				time = time + activity.getDuration()*convToHours;
			}
		}
		return round(time);
	}

	/** Genereert de gemiddelde rating (opgegeven bij invoegen, goed, slecht,...) van elk vak
	 * @param currStud de student
	 * @return Hashmap met naam van het vak en bijhorende gemiddelde rating 
	 */
		
	static public HashMap<String,Integer> getCourseAverageRating(Student currStud){
			ArrayList<SchoolActivity> schoolActivities = currStud.getOnlySchoolActs();
			HashMap<String,Integer> courseRating = new HashMap<String,Integer>();
			List<Course> courses = currStud.getCourses();
			Iterator<Course> iterator = courses.iterator();
			while(iterator.hasNext() == true){
				int rating = 0;
				int amountOfActivities = 0;
				int averageRating = 0;
				Course course = iterator.next();
				for(int j = 0; j != schoolActivities.size(); j++) {
					if(course.getName().equals(schoolActivities.get(j).getCourse().getName())) {
						rating += schoolActivities.get(j).getRating();
						amountOfActivities++;
					}
				}
				if(amountOfActivities != 0) {
					averageRating = rating/amountOfActivities;
				}
				courseRating.put(course.getName(), averageRating);
			}
			return courseRating;
		}
		
	/** Genereert de gemiddelde paginaSnelheid van elk vak
	 * @param currStud de student
	 * @return Hashmap met naam van het vak en bijhorende pagina's per uur 
	 */
		
	static public HashMap<String,Double> getAveragePageSpeed(Student currStud){
			ArrayList<SchoolActivity> schoolActivities = currStud.getOnlySchoolActs();
			HashMap<String, Double> courseSpeed = new HashMap<String, Double>();
			List<Course> courses = currStud.getCourses();
			Iterator<Course> iterator = courses.iterator();
			while(iterator.hasNext() == true){
				int pages = 0;
				long totalDuration = 0;
				double pageSpeed = 0;
				Course course = iterator.next();
				for(int j = 0; j != schoolActivities.size(); j++) {
					if(course.getName().equals(schoolActivities.get(j).getCourse().getName())) {
						pages += schoolActivities.get(j).getPages();
						totalDuration += schoolActivities.get(j).getDuration();
					}
				}
				if(totalDuration != 0) {
					pageSpeed = pages/(totalDuration*convToHours);
				}
				courseSpeed.put(course.getName(), pageSpeed);
			}
			return courseSpeed;
		}
		
	/** Genereert de afleidingen
	 * @param currStud de student
	 * @return HashMap met naam van de afleiding en bijhorende tijd
	 */
		
	static public HashMap<String,Double> getTopDistractions(Student currStud){
			ArrayList<SchoolActivity> schoolActivities = currStud.getOnlySchoolActs();
			HashMap<String, Double> topDistractions = new HashMap<String, Double>();
			for(int i = 0; i != schoolActivities.size(); i++) {
				for(int j = 0; j != schoolActivities.get(i).getDistractions().size(); j++) {
					String distraction = schoolActivities.get(i).getDistractions().get(j);
					double hours = (schoolActivities.get(i).getDuration())*convToHours;
					double duration = topDistractions.get(distraction) + hours;
					topDistractions.remove(distraction);
					topDistractions.put(distraction, duration);
				}
			}
			return topDistractions;
		}

		/** Genereert de productiefste dag van de week (maandag, dinsdag,...)
		* @param currStud de student
		* @return Hashmap met naam van de dag en bijhorende aantal tijd 
		*/
		
		static public HashMap<String,Double> getProductiveDay(Student currStud){
			ArrayList<SchoolActivity> schoolActivities = currStud.getOnlySchoolActs();
			HashMap<String, Double> productiveDay = new HashMap<String, Double>();
			Calendar cal = Calendar.getInstance();
			//initialiseren van hashMap
			productiveDay.put("Monday",0.0);
			productiveDay.put("Tuesday", 0.0);
			productiveDay.put("Wednesday", 0.0);
			productiveDay.put("Thursday", 0.0);
			productiveDay.put("Friday", 0.0);
			productiveDay.put("Saturday", 0.0);
			productiveDay.put("Sunday", 0.0);
			
			//hashmap opvullen met gegevens
			for(int i = 0; i != schoolActivities.size(); i++) {
				Date date = schoolActivities.get(i).getStart();
				cal.setTime(date);
				int weekDay = cal.get(Calendar.DAY_OF_WEEK);
				double hours = round((schoolActivities.get(i).getDuration())*convToHours);
				if (schoolActivities.get(i).getDuration() == null){
					// doe niets
				}
				else{
					String day = null;
					if(weekDay == 2) {
						day="Monday";
					}
					if(weekDay == 3) {
						day="Tuesday";
					}
					if(weekDay == 4) {
						day="Wednesday";
					}
					if(weekDay == 5) {
						day="Thursday";
					}
					if(weekDay == 6) {
						day="Friday";
					}
					if(weekDay == 7) {
						day = "Saturday";
					}
					if(weekDay == 1) {
						day = "Sunday";
					}
					double duration = productiveDay.get(day) + hours;
					productiveDay.remove(day);
					productiveDay.put(day, duration);
				}
			}
			return productiveDay;
		}
 
		/**
		 * Berekent de tijd gespendeerd aan een bepaald type andere activiteit
		 * @param currStud de student
		 * @return een hashmap met het type en het aantal miliseconden
		 */
		static public HashMap<String, Double> getFreeDistribution(Student currStud){
			Collection<Activity> activities = currStud.getAct();
			Iterator<Activity> iterator = activities.iterator();
			HashMap<String, Double> otherActivities = new HashMap<String, Double>();
			while(iterator.hasNext() == true){
				Activity activity = iterator.next();
				if(activity instanceof OtherActivity){
					String type = activity.getType();
					double duration = activity.getDuration()*convToHours;
					if(otherActivities.containsKey(type) == false){
						otherActivities.put(type, round(duration));
					}
					else{
						duration = duration + otherActivities.get(type);
						otherActivities.remove(type);
						otherActivities.put(type, round(duration));
					}
				}
			}
			return otherActivities;
		}
		
		/** Genereert de verdeling van freetime activiteiten
		* @param currStud de student
		* @return Hashmap met activiteiten en tijd
		*/
		static public HashMap<String,Double> schoolFree(Student currStud){
			ArrayList<SchoolActivity> schoolactivities = currStud.getOnlySchoolActs();
			Iterator<SchoolActivity> iteratorschool = schoolactivities.iterator();
			double durationSchool = 0;
			while(iteratorschool.hasNext() == true){
				SchoolActivity act = iteratorschool.next();
				if(act.getDuration() != null){
					durationSchool = durationSchool + act.getDuration()*convToHours;
				}
			}
			
			double durationFree = 0;
			Collection<Activity> activities = currStud.getAct();
			Iterator<Activity> iterator = activities.iterator();
			while(iterator.hasNext() == true){
				Activity activity = iterator.next();
				if(activity instanceof OtherActivity){
					durationFree = durationFree + activity.getDuration()*convToHours;
				}
			}
			
			HashMap<String,Double> schoolFree = new HashMap<String, Double>();
			schoolFree.put("School", round(durationSchool));
			schoolFree.put("Freetime", round(durationFree));
			return schoolFree;
		}
		
		/** Genereert gemiddelde tijd per vak over alle studenten
		* @param currStud de student
		* @return Hashmap met Vakken en tijd per vak
		*/
		static public HashMap<Course,Double> getAvgTimePerCourse(Student currStud){
			System.out.println("getAvgTimePerCourse");
			HashMap<Course,Double> totPerCourse = new HashMap<Course, Double>();
			HashMap<Course,Integer> numberOfPeoplePerCourse = new HashMap<Course, Integer>();
			HashMap<Course,Double> avgPerCourse = new HashMap<Course, Double>();
			List<Student> students = StudentManager.findAll();
			List<Course> courses = currStud.getCourses();
			
			for(Course c : courses){
				for(Student s : students){
					List<Course> otherStudCourses = s.getCourses();
					for(Course c2 : otherStudCourses){
						if(c.getName().equals(c2.getName())){
							double time = timeOfCourse(c,s);
							if(totPerCourse.get(c)!=null){
							time = totPerCourse.get(c) + timeOfCourse(c,s);
							}
							totPerCourse.put(c, time);
							int people = 1;
							if(numberOfPeoplePerCourse.get(c)!=null){
							people = numberOfPeoplePerCourse.get(c) + 1;
							}
							totPerCourse.put(c, time);
							numberOfPeoplePerCourse.put(c, people);
							}
					}
			  }
			}
			for(Course c : courses){
				double total = totPerCourse.get(c)*convToHours;
				int numberOfPeople = numberOfPeoplePerCourse.get(c);
				double avg = round(total/numberOfPeople);
				avgPerCourse.put(c, avg );
			}
			return avgPerCourse;
		}
 
				
}